

#include <stdlib.h>
#include "epd420RWS19A.h"

Epd::~Epd() {
};

Epd::Epd() {
    reset_pin = RST_PIN;
    dc_pin = DC_PIN;
    cs_pin = CS_PIN;
    busy_pin = BUSY_PIN;
    width = EPD_WIDTH;
    height = EPD_HEIGHT;
};

int Epd::Init(void) {
    /* this calls the peripheral hardware interface, see epdif */
    if (IfInit() != 0) {
        return -1;
    }
    /* EPD hardware init start */
    Reset();

    WaitUntilIdle();
    SendCommand(SW_RESET);
    WaitUntilIdle();

    SendCommand(DRIVER_OUTPUT_CONTROL);
    SendData((EPD_HEIGHT - 1) & 0xFF);
    SendData(((EPD_HEIGHT - 1) >> 8) & 0xFF);
    SendData(0x00);                     // GD = 0; SM = 0; TB = 0;

    SendCommand(DATA_ENTRY_MODE_SETTING);
    SendData(0x03);                     // X increment; Y increment

    SendCommand(SET_RAM_X_ADDRESS_START_END_POSITION);		//set Ram-X address start/end position
    SendData(0x00);                     		
    SendData(0x31); 								//0x31-->(49+1)*8=400

    SendCommand(SET_RAM_Y_ADDRESS_START_END_POSITION);		//set Ram-Y address start/end position
    SendData(0x00);                     		
    SendData(0x00);  
    SendData(0x2B);                     		
    SendData(0x01);     							//0x012B-->(299+1)=300

    SendCommand(BORDER_WAVEFORM_CONTROL);					//BORDER_WAVEFORM_CONTROL
    SendData(0x01);     

    SendCommand(WRITE_VCOM_REGISTER);					//VCOM Voltage
    SendData(0x4B); 

    SendCommand(GATE_DRIVING_VOLTAGE);					//GATE_ DRIVING_VOLTAGE
    SendData(LUT_DATA[70]);  

    SendCommand(SOURCE_DRIVING_VOLTAGE);					//SOURCE_ DRIVING_VOLTAGE
    SendData(LUT_DATA[71]);  
    SendData(LUT_DATA[72]);
    SendData(LUT_DATA[73]);  

    SendCommand(SET_DUMMY_LINE_PERIOD);					//SET_DUMMY_LINE_PERIOD
    SendData(LUT_DATA[74]);  

    SendCommand(SET_GATE_LINE_WIDTH);					//GATE_ DRIVING_VOLTAGE
    SendData(LUT_DATA[75]);   

    SetLut();									////LUT           

    SendCommand(SET_RAM_X_ADDRESS_COUNTER);				//SET_RAM_X_ADDRESS_COUNTER
    SendData(0x00);                     		
                                                                           		
    SendCommand(SET_RAM_Y_ADDRESS_COUNTER);				//SET_RAM_Y_ADDRESS_COUNTER
    SendData(0x2B);                     		
    SendData(0x01); 

    WaitUntilIdle();

    /* EPD hardware init end */
    return 0;
}

/**
 *  @brief: basic function for sending commands
 */
void Epd::SendCommand(unsigned char command) {
    DigitalWrite(dc_pin, LOW);
    SpiTransfer(command);
}

/**
 *  @brief: basic function for sending data
 */
void Epd::SendData(unsigned char data) {
    DigitalWrite(dc_pin, HIGH);
    SpiTransfer(data);
}

/**
 *  @brief: Wait until the busy_pin goes LOW
 */
void Epd::WaitUntilIdle(void) {
    while(DigitalRead(busy_pin) == HIGH) {      //LOW: idle, HIGH: busy
        DelayMs(100);
    }      
}

/**
 *  @brief: module reset.
 *          often used to awaken the module in deep sleep,
 *          see Epd::Sleep();
 */
void Epd::Reset(void) {
    DigitalWrite(reset_pin, LOW);                //module reset    
    DelayMs(200);
    DigitalWrite(reset_pin, HIGH);
    DelayMs(200);    
}

/**
 *  @brief: set the look-up table register
 */
void Epd::SetLut(void) {
    SendCommand(WRITE_LUT_REGISTER);
    /* the length of look-up table is 70 bytes */
    for (int i = 0; i < 70; i++) {
        SendData(LUT_DATA[i]);
    }
}



/**
 *  @brief: put an image buffer to the frame memory.
 *          this won't update the display.
 */
void Epd::SetFrameScreen_ALL(const unsigned char* frame_buffer_black, const unsigned char* frame_buffer_red) {
    if (frame_buffer_black != NULL) {
    	  SendCommand(WRITE_RAM_BW);
        /* Send black and white data */
        for (int i = 0; i< ALLSCREEN_BYTES; i++) { 
           SendData(frame_buffer_black[i]);     
        }
    }

    if (frame_buffer_red != NULL) {
    	  SendCommand(WRITE_RAM_RED);
        /* Send red data */
        for (int i = 0; i< ALLSCREEN_BYTES; i++) { 
           SendData(frame_buffer_red[i]);     
        }
    }
}
/**
 *  @brief: put an image buffer to the frame memory.
 *          this won't update the display.
 */
void Epd::SetFrameScreen_BW(const unsigned char* frame_buffer_black) {
    if (frame_buffer_black != NULL) {
    	  SendCommand(WRITE_RAM_BW);
        /* Send black and white data */
        for (int i = 0; i< ALLSCREEN_BYTES; i++) { 
           SendData(frame_buffer_black[i]);     
        }
    }
}
/**
 *  @brief: put an image buffer to the frame memory.
 *          this won't update the display.
 */
void Epd::SetFrameScreen_RED(const unsigned char* frame_buffer_red) {
    if (frame_buffer_red != NULL) {
    	  SendCommand(WRITE_RAM_RED);
        /* Send red data */
        for (int i = 0; i< ALLSCREEN_BYTES; i++) { 
           SendData(frame_buffer_red[i]);     
        }
    }
}


/**
 *  @brief: clear the frame memory with the specified color.
 *          this won't update the display.
 */
void Epd::ClearFrameMemory(void) {
    SendCommand(WRITE_RAM_BW);
    /* write RAM for black(0)/white (1) */
    for (int i = 0; i < ALLSCREEN_BYTES; i++) {
        SendData(0xFF);
    }

    SendCommand(WRITE_RAM_RED);
    /* write RAM for red(1)/white (0) */
    for (int i = 0; i < ALLSCREEN_BYTES; i++) {
        SendData(0x00);
    }
}

/**
 *  @brief: update Full screen refresh
 */
void Epd::DisplayFrame(void) {
    SendCommand(DISPLAY_UPDATE_CONTROL_2);
    SendData(0xC7);
    SendCommand(MASTER_ACTIVATION);
    WaitUntilIdle();
}


/**
 *  @brief: After this command is transmitted, the chip would enter the 
 *          deep-sleep mode to save power. 
 *          The deep sleep mode would return to standby by hardware reset. 
 *          You can use Epd::Init() to awaken
 */
void Epd::Sleep() {
    SendCommand(DEEP_SLEEP_MODE);
    SendData(DRIVER_OUTPUT_CONTROL);
    DelayMs(100);    
}



const unsigned char LUT_DATA[]= {
0x2,	0x84,	0x84,	0x10,	0x0,	0x0,	0x4,
0x4,	0x84,	0x84,	0x80,	0x0,	0x0,	0x20,
0xA0,	0x84,	0x84,	0x9,	0x8C,	0x8C,	0xC3,
0xA0,	0x84,	0x84,	0x9,	0x8C,	0x8C,	0xC3,
0x0,	0x0,	0x0,	0x0,	0x0,	0x0,	0x0,
0xF,	0xA,	0xC,	0xF,	0x1,		
0x2,	0x0,	0x2,	0x0,	0xE,		
0x1,	0x0,	0x1,	0x0,	0x31,		
0xC,	0xD,	0x7,	0x2,	0x1,		
0x3,	0x0,	0x19,	0x0,	0x4,		
0x2,	0x0,	0x12,	0x0,	0x5,		
0xA,	0x0,	0x4,	0x12,	0x0,		
0x17,	0x41,	0xA8,	0x32,			
0x2C,	0x0A
};	

/* END OF FILE */


